package com.itcam.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.common.Constants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itcam.tingshu.album.client.TrackInfoFeignClient;
import com.itcam.tingshu.common.constant.KafkaConstant;
import com.itcam.tingshu.common.constant.RedisConstant;
import com.itcam.tingshu.common.constant.SystemConstant;
import com.itcam.tingshu.common.result.Result;
import com.itcam.tingshu.common.service.KafkaService;
import com.itcam.tingshu.model.album.TrackInfo;
import com.itcam.tingshu.model.user.*;
import com.itcam.tingshu.user.client.VipServiceConfigFeignClient;
import com.itcam.tingshu.user.factory.PaymentStrategyFactory;
import com.itcam.tingshu.user.mapper.*;
import com.itcam.tingshu.user.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itcam.tingshu.user.service.UserPaidTrackService;
import com.itcam.tingshu.user.strategy.PaymentStrategy;
import com.itcam.tingshu.vo.user.UserInfoVo;
import com.itcam.tingshu.vo.user.UserPaidRecordVo;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.joda.time.LocalDateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;


import javax.xml.crypto.dsig.TransformService;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    // 重新注入缓存自己的对象，不能使用系统自带的对象
    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private KafkaService kafkaService;

    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;

    @Qualifier("com.itcam.tingshu.album.client.TrackInfoFeignClient")
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private UserPaidTrackService userPaidTrackService;

    @Autowired
    private VipServiceConfigMapper vipServiceConfigMapper;

    @Autowired
    private UserVipServiceMapper userVipServiceMapper;

    @Autowired
    private PaymentStrategyFactory paymentStrategyFactory;

    /**
     * 微信登录
     * @param code
     * @return
     */
    @Override
    // @Transactional(rollbackFor = Exception.class) 本地事务 —— 只能关联当前的微服务user；不能处理account
    public Map<String, Object> wxLogin(String code) {
        // 通过Code换取openid；每个微信用户对应唯一的openid
        String openid = null;
        try {
            openid = wxMaService.jsCode2SessionInfo(code).getOpenid();
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        // 通过openid查询用户是否注册过
        // select wx_open_id from user_info where wx_open_id = 'oY-YBwNhKXkX7Z_6Y7K6Z3_KJZ8U';
        UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getWxOpenId, openid));
        if (null == userInfo) {
            // 实现注册功能
            userInfo = new UserInfo();
            userInfo.setWxOpenId(openid);
            userInfo.setNickname("听友：" + System.currentTimeMillis());
            userInfo.setAvatarUrl("https://sky-itcast-version-cam.oss-cn-heyuan.aliyuncs.com/53e354a8-9f60-4c6c-b1e0-c74d7807bb0b.png");
            // 保存数据
            this.save(userInfo);

            // 初始化账户信息 —— 跨微服务操作 userAccountFeignClient.initUserAccount(userInfo.getId(),100,100); 同步
            // 要是初始化账户信息失败了怎么办？回滚账户注册信息，本地事务解决不了，使用分布式事务! 【seata】

            // 异步，能够提高效率，实现解耦
            // 发送消息需要传递什么参数？
            //      参数一：topics
            //      参数二：消息主题 —— ❗消息内容由消费者的需求（初始化账户信息）决定的
            /*
                service-account:消费者——初始化账户信息——要传用户id
                service_user:生产者——
             */
            kafkaService.sendMsg(KafkaConstant.QUEUE_USER_REGISTER, userInfo.getId().toString());
        }
        // 不为空，注册过，返回token，并将数据放入缓存中
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 声明一个key来记录
        String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
        this.redisTemplate.opsForValue().set(loginKey, userInfo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        // 返回数据
        return map;
    }

    /**
     * 获取用户信息
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {
        // select * from user_info where id = userId;
        UserInfo userInfo = this.getById(userId);
        if (null == userInfo) {
            return null;
        }
        // 属性拷贝
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);
        // 返回数据
        return userInfoVo;
    }

    /**
     * 修改用户信息
     * @param userInfoVo
     * @param userId
     */
    @Override
    public void updateUser(UserInfoVo userInfoVo, Long userId) {
        // 创建用户对象
        UserInfo userInfo = new UserInfo();
        // 修改用户信息
        BeanUtils.copyProperties(userInfoVo, userInfo);
        userInfo.setId(userId);
        // 调用修改方法
        this.updateById(userInfo);
    }

    /**
     * 判断用户是否购买声音列表
     * @param albumId
     * @param trackIdList
     * @param userId
     * @return
     */
    @Override
    public Map<Long, Integer> userIsPaidTrack(Long albumId, List<Long> trackIdList, Long userId) {
        // 查看用户是否购买过专辑，如果购买过专辑，则需要付费的声音Id集合都需要免费，user_paid_album
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(
                new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getAlbumId, userId)
        );
        // 判断是否为空

        if (null != userPaidAlbum) {
            // 处理数据 1.表示免费 0.表示付费
            Map<Long, Integer> map = trackIdList.stream()
                    .collect(Collectors.toMap(trackId -> trackId, trackId -> 1));
            // trackIdList.stream()
            //         .collect(Collectors.toMap(trackId -> trackId, trackId -> 0));
            // 返回数据
            return map;
        }
        // 判断用户是否购买过当前专辑的声音，user_paid_track
        // select * from user_paid_track paid where user_id = ? and album_id = 1329 and track_id in (trackIdList);
        // LambdaQueryWrapper<UserPaidTrack> wrapper = new LambdaQueryWrapper<>();
        // wrapper.eq(UserPaidTrack::getUserId, userId).eq(UserPaidTrack::getAlbumId, albumId).in(UserPaidTrack::getTrackId, trackIdList);
        // 获取到当前这个用户购买过的声音Id列表
        List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>()
                .eq(UserPaidTrack::getUserId, userId)
                .eq(UserPaidTrack::getAlbumId, albumId)
                .in(UserPaidTrack::getTrackId, trackIdList));
        // 判断trackIdList这个集合中的声音Id，是否有购买过的声音Id
        HashMap<Long, Integer> map = new HashMap<>();
        for (Long trackId : trackIdList) {
            // 解决空指针问题
            if (CollectionUtils.isEmpty(userPaidTrackList)) {
                map.put(trackId, 0);
            } else {
                // 判断userPaidTrackIdList集合中是否包含trackId
                if (userPaidTrackList.contains(trackId)) {
                    map.put(trackId, 1);
                } else {
                    map.put(trackId, 0);
                }
            }
        }
        // 返回数据
        return map;
    }

    /**
     * 判断用户是否购买过专辑
     * @param albumId
     * @param userId
     * @return
     */
    @Override
    public Boolean isPaidAlbum(Long albumId, Long userId) {
        // 根据用户Id与专辑Id查询是否有记录
        return userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getAlbumId, albumId).eq(UserPaidAlbum::getUserId, userId)) != null;
    }

    /**
     * 根据专辑Id获取到用户已支付声音Id列表
     * @param userId
     * @param albumId
     * @return
     */
    @Override
    public List<Long> findUserPaidTrackList(Long userId, Long albumId) {
        // select * from user_paid_track track where user_id = 26 and album_id = 341;
        return userPaidTrackMapper.selectList(
                        new LambdaQueryWrapper<UserPaidTrack>()
                                .eq(UserPaidTrack::getAlbumId, albumId)
                                .eq(UserPaidTrack::getUserId, userId)
                ).stream()
                .map(UserPaidTrack::getTrackId)
                .collect(Collectors.toList());
    }

    /**
     * 用户支付记录
     * @param userPaidRecordVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userPayRecord(UserPaidRecordVo userPaidRecordVo) {
        // 判断用户购买类型
        // 项目类型 1001-专辑 1002-声音 1003-vip会员
//        if (userPaidRecordVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)) {
//            // 防止重复消费，如果有记录则直接停止
////            LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getOrderNo, userPaidRecordVo.getOrderNo());
////            Long count = userPaidAlbumMapper.selectCount(queryWrapper);
////            if (count != 0) return;
//            // 先查询这个用户记录表中是否已经存储数据了
//            // select*from user_paid_album where user_id = ? and album_id = ?
//            // 根据订单编号查询是否有当前订单 select*from user_paid_album where order_no = ?
//            UserPaidAlbum userPaidAlbumQuery = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>());
//            if (userPaidAlbumQuery != null)
//                return;
//
//            // 购买专辑 user_paid_album
//            UserPaidAlbum userPaidAlbum = new UserPaidAlbum();
//            // 赋值
//            userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
//            userPaidAlbum.setUserId(userPaidRecordVo.getUserId());
//            userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
//            // 保存
//            userPaidAlbumMapper.insert(userPaidAlbum);
//        } else if (userPaidRecordVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)) {
//            // 购买声音
//            // 防止重复消费
//            LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getOrderNo, userPaidRecordVo.getOrderNo());
//            Long count = userPaidTrackMapper.selectCount(queryWrapper);
//            if (count != 0) return;
//            // 通过声音Id声音对象
//            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0));
//            Assert.notNull(trackInfoResult, "专辑结果集不能为空");
//            TrackInfo trackInfo = trackInfoResult.getData();
//            Assert.notNull(trackInfo, "专辑不能为空");
//            List<UserPaidTrack> userPaidTrackList = userPaidRecordVo.getItemIdList().stream()
//                    .map(itemId -> {
//                        UserPaidTrack userPaidTrack = new UserPaidTrack();
//                        // 赋值
//                        userPaidTrack.setUserId(userPaidRecordVo.getUserId());
//                        userPaidTrack.setAlbumId(trackInfo.getAlbumId());
//                        userPaidTrack.setTrackId(itemId);
//                        userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
//                        return userPaidTrack;
//                    })
//                    .collect(Collectors.toList());
//            userPaidTrackService.saveBatch(userPaidTrackList);
//        } else if (userPaidRecordVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_VIP)) {
//            // 购买会员
//            //防止重复消费
//            LambdaQueryWrapper<UserVipService> queryWrapper = new LambdaQueryWrapper<UserVipService>().eq(UserVipService::getOrderNo, userPaidRecordVo.getOrderNo());
//            Long count = userVipServiceMapper.selectCount(queryWrapper);
//            if (count != 0) return;
//            // 查询用户购买vip时间
//            Long itemId = userPaidRecordVo.getItemIdList().get(0);
//            //  根据Id查询vip服务配置对象
//            VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(itemId);
//            Integer serviceMonth = vipServiceConfig.getServiceMonth();
//            // 创建对象
//            UserVipService userVipService = new UserVipService();
//            /// 赋值
//            userVipService.setUserId(userPaidRecordVo.getUserId());
//            userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
//            userVipService.setStartTime(new Date());
//            // 过期时间：
//            // 1.第一次购买当前时间+购买月份！  第二次购买可能会发生--续费： 当前过期时间+续费时间！
//            // 2.如何判断是否续费：是否vip and vip_expire > 当前系统时间
//            UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
//            // 判断
//            if (null != userInfo && userInfo.getIsVip() == 1 && userInfo.getVipExpireTime().after(new Date())) {
//                // userInfo.getVipExpireTime() + userInfo.getServiceMonth();
//                LocalDateTime localDate = new LocalDateTime(userInfo.getVipExpireTime());
//                Date expireTime = localDate.plusMonths(serviceMonth).toDate();
//                userVipService.setExpireTime(expireTime);
//            } else {
//                // 不是续费情况
//                userVipService.setExpireTime(new LocalDateTime().plusMonths(serviceMonth).toDate());
//            }
//            // 保存数据
//            userVipServiceMapper.insert(userVipService);
//            // 普通用户变为vip    user_info.is_vip = 1;
//            userInfo.setIsVip(1);
//            userInfo.setVipExpireTime(userVipService.getExpireTime());
//            userInfoMapper.updateById(userInfo);
//        } else {
//            log.info("无该项目类型：{}", JSON.toJSONString(userPaidRecordVo));
//        }

        // 调用工厂实现类
        PaymentStrategy strategy = paymentStrategyFactory.getStrategy(userPaidRecordVo.getItemType());
        strategy.processPayment(userPaidRecordVo);
    }

    /**
     * 更新Vip到期失效状态
     */
    @Override
    public void updateVipExpireStatus() {
        // 1.查询哪些是vip失效的用户，并将is_vip设置为0
        // update user_info set is_vip = 0 where vip_expire_time < now() and is_vip = 1 and is_deleted = 0;
        userInfoMapper.updateVipExpireStatus();
    }


}
